package org.yi.web.security;

import java.util.List;

import javax.sql.DataSource;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.yi.core.common.Constants;
import org.yi.core.enums.AccountStateEnums;
import org.yi.web.account.entity.AccountEntity;
import org.yi.web.security.entity.PermissionEntity;
import org.yi.web.security.entity.RoleEntity;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.DbKit;

public class ShiroRealm extends JdbcRealm {

	/**
	 * authorization
	 */
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		
		String loginname = String.valueOf(principal.iterator().next());
		AccountEntity user = AccountEntity.dao.getByName(loginname);
		
		if(user != null){
			//one user has one role only
			RoleEntity role = RoleEntity.dao.getRoleByName(user.getStr("role"));
			info.addRole(role.getStr("name"));
			
			List<PermissionEntity> permissions = PermissionEntity.dao.getPermissinsByRole(role);
			for(PermissionEntity p : permissions) 
				info.addStringPermission(p.getStr("name"));
		}
		
		return info;
	}

	/**
	 * login authentication
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		
		UsernamePasswordToken upt = (UsernamePasswordToken) token ;
		
		String loginname = upt.getUsername().trim();
		String password = String.valueOf(upt.getPassword());
		
		//determine whether an agent exists
		AccountEntity user = AccountEntity.dao.getByName(loginname);
		
		//if exists, determine whether the password is right or not
		if(user != null){
			// if password is blank or password not equal to passwd parameter, it declare passwd parameter wrong
			if(StrKit.isBlank(password) || !password.equals(user.getStr("passwd"))){
				throw new IncorrectCredentialsException("password error!");
			} else if(AccountStateEnums.LOCK.getCode() == user.getInt("state")){
				throw new LockedAccountException(" account [" + loginname + "] locked.");
			} else {
				Session session = SecurityUtils.getSubject().getSession();
				session.setAttribute(Constants.KEY_LOGIN_ACCOUNT, user);
				return new SimpleAuthenticationInfo(loginname, password,  getName());
			}
		}else{
			throw new UnknownAccountException("loginname: " + loginname + " not exist!");
		}
	}

	@Override
	public void setDataSource(DataSource dataSource) {
		super.setDataSource(DbKit.getConfig().getDataSource());
	}

	
	
}
